// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include <zencore/string.h>
#include <zencore/zencore.h>
#if ZEN_PLATFORM_WINDOWS
#	include <zencore/windows.h>
#else
#	include <errno.h>
#endif
#if __has_include("source_location")
#	include <source_location>
#endif
#include <string>
#include <system_error>

namespace zen {

#if ZEN_PLATFORM_WINDOWS
ZENCORE_API void ThrowSystemException [[noreturn]] (HRESULT hRes, std::string_view Message);
#endif	// ZEN_PLATFORM_WINDOWS

#if defined(__cpp_lib_source_location)
ZENCORE_API void ThrowLastErrorImpl [[noreturn]] (std::string_view Message, const std::source_location& Location);
ZENCORE_API void ThrowOutOfMemoryImpl [[noreturn]] (std::string_view Message, const std::source_location& Location);
#	define ThrowLastError(Message)	  ThrowLastErrorImpl(Message, std::source_location::current())
#	define ThrowOutOfMemory(Message) ThrowOutOfMemoryImpl(Message, std::source_location::current())
#else
ZENCORE_API void ThrowLastError [[noreturn]] (std::string_view Message);
ZENCORE_API void ThrowOutOfMemory [[noreturn]] (std::string_view Message);
#endif

ZENCORE_API void ThrowSystemError [[noreturn]] (uint32_t ErrorCode, std::string_view Message);

ZENCORE_API std::string GetLastErrorAsString();
ZENCORE_API std::string GetSystemErrorAsString(uint32_t Win32ErrorCode);

inline int32_t
GetLastError()
{
#if ZEN_PLATFORM_WINDOWS
	return ::GetLastError();
#else
	return errno;
#endif
}

inline std::error_code
MakeErrorCode(uint32_t ErrorCode) noexcept
{
	return std::error_code(ErrorCode, std::system_category());
}

inline std::error_code
MakeErrorCodeFromLastError() noexcept
{
	return std::error_code(zen::GetLastError(), std::system_category());
}

//////////////////////////////////////////////////////////////////////////

class OptionParseException : public std::runtime_error
{
public:
	inline explicit OptionParseException(const std::string& Message) : std::runtime_error(Message) {}
};

bool IsOOM(const std::system_error& SystemError);
bool IsOOD(const std::system_error& SystemError);

}  // namespace zen
